<template>
  <el-container>
    <el-header
      class="header"
    >
      <QueryForm
        ref="queryFormRef"
        :model="queryForm.data"
        :role-selector="queryForm.roleSelector"
        @query="handleQueryFormQuery"
        @reset="handleQueryFormReset"
        @selector-show="handleQueryFormSelectorShow"
      >
      </QueryForm>
    </el-header>
    <el-container>
      <el-aside
        v-show="subsystemManager.isVisible"
      >
        <SubsystemManager
          class="subsystemManager"
          :is-loading="subsystemManager.isLoading"
          :tree-data="subsystemManager.treeData"
          @query="handleSubsystemManagerQuery"
        >
        </SubsystemManager>
      </el-aside>
      <el-main>
        <ControlButtonGroup
          :disabled-array="controlButtonGroupDisabledArray"
          :is-status-change-button-loading="controlButtonGroup.isStatusChangeButtonLoading"
          @add="handleControlButtonGroupAdd"
          @arrow-toggle="handleControlButtonGroupArrowToggle"
          @command="handleControlButtonGroupCommand"
          @copy="handleControlButtonGroupCopy"
          @delete="handleControlButtonGroupDelete"
          @refresh="handleControlButtonGroupRefresh"
          @role-allocate="handleControlButtonGroupRoleAllocate"
          @status-change="handleControlButtonGroupStatusChange"
          @view-manager-show="handleControlButtonGroupViewManagerShow"
        >
        </ControlButtonGroup>
        <UserDataTable
          ref="userDataTableRef"
          :column-array="userDataTable.columnArray"
          :data-array="userDataTable.dataArray"
          :is-loading="userDataTable.isLoading"
          :pagination="userDataTable.pagination"
          @current-change="handleUserDataTablePageNumChange"
          @copy="handleUserDataTableCopy"
          @delete="handleUserDataTableDelete"
          @edit="handleUserDataTableEdit"
          @role-click="handleUserDataTableRoleClick"
          @selection-change="handleUserDataTableSelectionChange"
          @size-change="handleUserDataTablePageSizeChange"
        >
        </UserDataTable>
        <UserDataForm
          ref="userDataFormRef"
          :department-selector="userDataForm.departmentSelector"
          :is-loading="userDataForm.isLoading"
          :is-visible.sync="userDataForm.isVisible"
          :model="userDataForm.data"
          :position-selector="userDataForm.positionSelector"
          :role-selector="userDataForm.roleSelector"
          @department-selector-show="handleUserDataFormDepartmentSelectorShow"
          @position-selector-show="handleUserDataFormPositionSelectorShow"
          @role-selector-show="handleUserDataFormRoleSelectorShow"
          @submit="handleUserDataFormSubmit"
        ></UserDataForm>
        <RoleAllocator
          :is-loading="roleAllocator.isLoading"
          :is-visible.sync="roleAllocator.isVisible"
          :pagination="roleAllocator.pagination"
          :table="roleAllocator.table"
          @current-change="handleRoleAllocatorPageNumChange"
          @size-change="handleRoleAllocatorPageSizeChange"
          @submit="handleRoleAllocatorSubmit"
        ></RoleAllocator>
        <ResourceAllocator
          ref="resourceAllocatorRef"
          :checked-id-array="resourceAllocator.checkedIdArray"
          :is-loading="resourceAllocator.isLoading"
          :is-visible.sync="resourceAllocator.isVisible"
          :total-data-array="resourceAllocator.totalDataArray"
        >
        </ResourceAllocator>
        <ViewManager
          :is-visible.sync="viewManager.isVisible"
          :item-array="userDataTable.columnArray"
          @save="handleViewManagerSave"
        >
        </ViewManager>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>
/**
 * @typedef {{
 *   'label': String,
 *   'value': String,
 * }} SelectorData 下拉菜单选项的数据
 * @typedef {{
 *   'id': String,
 * }} Row 表格一行的数据
 * @typedef {{
 *   'birthday': String,
 *   'code': String,
 *   'departmentId': String,
 *   'email': String,
 *   'name': String,
 *   'other': String,
 *   'password': String,
 *   'positionId': String,
 *   'remark': String,
 *   'roleList': {
 *     'id': String,
 *   }[],
 *   'sex': 0 | 1,
 *   'tel': String,
 * }} UserDataFormData `用户数据表单`的数据
 * @typedef {{
 *   'birthday': String,
 *   'code': String,
 *   'company': String,
 *   'department': String,
 *   'id': String,
 *   'name': String,
 *   'position': String,
 *   'role': String,
 *   'sex': String,
 *   'status': Number,
 *   'tel': String,
 * }} UserDataTableData `用户数据表格`的数据
 */
import {
  add,
  batchRemove,
  batchUpdate,
  commonQuery,
  modify,
  modifyWithNewRole,
  queryAllDepartment,
  queryAllPosition,
  queryAllRole,
  queryUserById,
  remove,
} from '@/api/right/user'

import ControlButtonGroup from './ControlButtonGroup.vue'
import QueryForm from './QueryForm.vue'
import ResourceAllocator from './ResourceAllocator.vue'
import RoleAllocator from './RoleAllocator.vue'
import SubsystemManager from './SubsystemManager.vue'
import UserDataForm from './UserDataForm.vue'
import UserDataTable from './UserDataTable.vue'
import ViewManager from './ViewManager.vue'

import {
  commonQuery as queryRoleArray,
} from '@/api/right/role'
import {
  treeQuery,
} from '@/api/right/resource'

/**
 * 获取`部门数组`
 * @return {Promise<SelectorData[]>}
 */
const getDepartmentArray = async () => {
  try {
    return (await queryAllDepartment()).data.map(({
      'id': value,
      'name': label,
    }) => {
      return {
        label,
        value,
      }
    })
  } catch (error) {
    console.error(error)
  }
  throw new Error('查询部门时出错')
}
/**
 * 获取`职位数组`
 * @return {Promise<SelectorData[]>}
 */
const getPositionArray = async () => {
  try {
    return (await queryAllPosition()).data.map(({
      'id': value,
      'name': label,
    }) => {
      return {
        label,
        value,
      }
    })
  } catch (error) {
    console.error(error)
  }
  throw new Error('查询职位时出错')
}
/**
 * 获取`角色数组`
 * @return {Promise<SelectorData[]>}
 */
const getRoleArray = async () => {
  try {
    return (await queryAllRole()).data.map(({
      'id': value,
      'name': label,
    }) => {
      return {
        label,
        value,
      }
    })
  } catch (error) {
    console.error(error)
  }
  throw new Error('查询角色时出错')
}
/**
 * 获取`用户数据表单`的数据
 * @param {String} id 用户的`id`属性
 * @return {Promise<UserDataFormData>}
 */
const getUserDataFormData = async (id) => {
  try {
    const {
      birthday,
      code,
      departmentId,
      email,
      name,
      other,
      positionId,
      remark,
      roleList,
      sex,
      tel,
    } = await queryUserById(id)
    return {
      birthday,
      code,
      departmentId,
      email,
      name,
      other,
      'password': '',
      positionId,
      remark,
      roleList,
      sex,
      tel,
    }
  } catch (error) {
    console.error(error)
  }
  throw new Error('查询用户数据时出错')
}
/**
 * 获取用户数据的`version`属性
 * @param {String} id 用户数据的`id`属性
 * @return {Promise<String>} version
 */
const getUserDataVersionById = async (id) => {
  try {
    return (await queryUserById(id)).version
  } catch (error) {
    console.error(error)
  }
  throw new Error('查询用户数据版本时出错')
}

export default {
  'name': 'User',

  'components': {
    ControlButtonGroup,
    QueryForm,
    ResourceAllocator,
    RoleAllocator,
    SubsystemManager,
    UserDataForm,
    UserDataTable,
    ViewManager,
  },

  'data' () {
    return {
      /**
       * `控制按钮组`
       */
      'controlButtonGroup': {
        'isStatusChangeButtonLoading': false,
      },
      /**
       * `查询表单`
       */
      'queryForm': {
        'data': {
          'code': '',
          'name': '',
          'roleId': '',
          'tel': '',
        },
        'roleSelector': {
          'array': [],
          'isLoading': false,
        },
      },
      /**
       * `资源分配器`
       */
      'resourceAllocator': {
        'checkedIdArray': [],
        'isLoading': false,
        'isVisible': false,
        'totalDataArray': [],
      },
      /**
       * `角色分配器`
       */
      'roleAllocator': {
        'isLoading': false,
        'isVisible': false,
        'pagination': {
          'number': 1,
          'size': 10,
          'total': 0,
        },
        'table': {
          'dataArray': [],
          'isLoading': false,
          'selectedRowArray': [],
        },
      },
      /**
       * `子系统管理器`
       */
      'subsystemManager': {
        'isLoading': false,
        'isVisible': false,
        'queryParameters': {},
        'treeData': [
          {
            'children': [],
            'label': '部门',
          },
          {
            'children': [],
            'label': '职位',
          },
          {
            'children': [],
            'label': '角色',
          },
        ],
      },
      /**
       * `用户数据表单`
       */
      'userDataForm': {
        'data': {
          'birthday': '',
          'code': '',
          'departmentId': '',
          'email': '',
          'name': '',
          'other': '',
          'password': '',
          'positionId': '',
          'remark': '',
          'roleList': [],
          'sex': null,
          'tel': '',
        },
        'departmentSelector': {
          'array': [],
          'isLoading': false,
        },
        'id': '',
        'isLoading': false,
        'isVisible': false,
        // 两种模式：增加（add）、编辑（edit）
        'mode': 'add',
        'positionSelector': {
          'array': [],
          'isLoading': false,
        },
        'roleSelector': {
          'array': [],
          'isLoading': false,
        },
      },
      /**
       * `用户数据表格`
       */
      'userDataTable': {
        'columnArray': [
          {
            'isVisible': true,
            'label': '工号',
            'prop': 'code',
            'width': '128',
          },
          {
            'isVisible': true,
            'label': '用户名',
            'prop': 'name',
            'width': '128',
          },
          {
            'isVisible': true,
            'label': '所属公司',
            'prop': 'company',
            'width': '100',
          },
          {
            'isVisible': true,
            'label': '所属部门',
            'prop': 'department',
            'width': '100',
          },
          {
            'isVisible': true,
            'label': '所属角色',
            'prop': 'role',
            'width': '256',
          },
          {
            'isVisible': true,
            'label': '职位',
            'prop': 'position',
            'width': '100',
          },
          {
            'isVisible': true,
            'label': '性别',
            'prop': 'sex',
            'width': '100',
          },
          {
            'isVisible': true,
            'label': '生日',
            'prop': 'birthday',
            'width': '100',
          },
          {
            'isVisible': true,
            'label': '电话',
            'prop': 'tel',
            'width': '120',
          },
          {
            'isVisible': true,
            'label': '状态',
            'prop': 'status',
            'width': '100',
          },
        ],
        'dataArray': [],
        'isLoading': false,
        'pagination': {
          'number': 1,
          'size': 10,
          'total': 0,
        },
        'selectedRowArray': [],
      },
      /**
       * `视图管理器`
       */
      'viewManager': {
        'isVisible': false,
      },
    }
  },

  'computed': {
    /**
     * 设置`控制按钮组`里的按钮是否无效的计算属性组成的数组
     *
     * 如果`用户数据表格`没有勾选任何行，则使其处于无效状态，使用户无法点击
     */
    'controlButtonGroupDisabledArray' () {
      const {
        length,
      } = this.userDataTable.selectedRowArray
      return [
        false,
        false,
        length === 0,
        length === 0,
        length === 0,
        length === 0,
        false,
        false,
      ]
    },
  },

  'created' () {
    this.setUserDataTableData()
  },

  'methods': {
    /**
     * 在`用户数据表格`中增加一条用户数据
     */
    async 'addUser' () {
      const {
        $message,
        userDataForm,
      } = this
      const {
        data,
      } = userDataForm
      const {
        code,
        tel,
      } = data
      if ((await this.getUserDataTableData({
        code,
      })).dataArray.some(({
        'code': userCode,
      }) => {
        return userCode === code
      })) {
        throw new Error('工号不能重复')
      } else if ((await this.getUserDataTableData({
        tel,
      })).dataArray.some(({
        'tel': userTel,
      }) => {
        return userTel === tel
      })) {
        throw new Error('电话不能重复')
      }
      try {
        if (await add(data)) {
          $message({
            'message': '增加成功',
            'type': 'success',
          })
          return
        }
      } catch (error) {
        console.error(error)
      }
      throw new Error('增加用户数据时出错')
    },
    /**
     * 将在`角色分配器`里被勾选的角色分配给`用户数据表格`里被勾选的用户
     */
    async 'allocateRoleToUser' () {
      const {
        $message,
        roleAllocator,
        userDataTable,
      } = this
      const {
        table,
      } = roleAllocator
      const load = userDataTable.selectedRowArray.map(({
        id,
      }) => {
        return {
          id,
          'roleList': table.selectedRowArray.map(({
            'id': roleId,
          }) => {
            return {
              'id': roleId,
            }
          }),
        }
      })
      try {
        if (await modifyWithNewRole(load)) {
          $message({
            'message': '分配成功',
            'type': 'success',
          })
          return
        }
      } catch (error) {
        console.error(error)
      }
      throw new Error('分配角色时出错')
    },
    /**
     * 清空`查询表单`
     */
    'clearQueryForm' () {
      this.queryForm.data = {
        'code': '',
        'name': '',
        'roleId': '',
        'tel': '',
      }
    },
    /**
     * 清空`子系统管理器`的选择项
     */
    'clearSubsystemManager' () {
      this.subsystemManager.queryParameters = {}
    },
    /**
     * 复制一个用户数据
     *
     * 该函数用于将`用户数据表格`的单行复制和`控制按钮组`的复制的两个操作整合在一起
     * @param {String} id 用户数据的`id`属性
     */
    async 'copyUserData' (id) {
      const {
        $message,
        $refs,
        userDataForm,
      } = this
      const {
        departmentSelector,
        positionSelector,
        roleSelector,
      } = userDataForm
      userDataForm.isLoading = true
      userDataForm.mode = 'add'
      userDataForm.isVisible = true
      try {
        (await Promise.all([
          getDepartmentArray(),
          getPositionArray(),
          getRoleArray(),
        ])).forEach((value, index) => {
          [
            departmentSelector,
            positionSelector,
            roleSelector,
          ][index].array = value
        })
        userDataForm.data = await getUserDataFormData(id)
        this.$nextTick(() => {
          $refs.userDataFormRef.setInnerModel()
        })
      } catch (error) {
        $message.error(error.message)
      }
      userDataForm.isLoading = false
    },
    /**
     * 删除确认框，用来确认是否删除并且展示加载动画
     * @param {Function} task 点击`确定`后的任务，以回调函数形式传入
     */
    'deleteConfirm' (task) {
      return this.$confirm(
        '确定删除（不可恢复）？',
        '删除确认',
        {
          async 'beforeClose' (action, instance, done) {
            if (action !== 'confirm') {
              done()
              return
            }
            instance.confirmButtonLoading = true
            instance.confirmButtonText = ''
            instance.showCancelButton = false
            instance.message = '正在删除...'
            await task()
            done()
          },
          'cancelButtonText': '取消',
          'confirmButtonLoading': false,
          'confirmButtonText': '确定',
          'showCancelButton': true,
          'type': 'warning',
        },
      )
    },
    /**
     * 删除被勾选的`用户数据表格`行的用户数据
     */
    async 'deleteSelectedUserArray' () {
      const {
        $message,
        userDataTable,
      } = this
      const {
        selectedRowArray,
      } = userDataTable
      const load = await Promise.all(selectedRowArray.map(async ({
        id,
      }) => {
        return {
          id,
          'version': await getUserDataVersionById(id),
        }
      }))
      try {
        if (await batchRemove(load)) {
          $message({
            'message': '删除成功',
            'type': 'success',
          })
          return
        }
      } catch (error) {
        console.error(error)
      }
      throw new Error('删除用户数据时出错')
    },
    /**
     * 删除`用户数据表格`的一行的用户数据
     * @param {Row} row `用户数据表格`的一行
     */
    async 'deleteUser' (row) {
      const {
        $message,
      } = this
      try {
        if (await remove(
          row.id,
          await getUserDataVersionById(row.id),
        )) {
          $message({
            'message': '删除成功',
            'type': 'success',
          })
          return
        }
      } catch (error) {
        console.error(error)
      }
      throw new Error('删除用户数据时出错')
    },
    /**
     * 修改`用户数据表格`的一行的用户数据
     */
    async 'editUser' () {
      const {
        $message,
        userDataForm,
      } = this
      const {
        data,
        id,
      } = userDataForm
      const {
        code,
        tel,
      } = data
      if ((await this.getUserDataTableData({
        code,
      })).dataArray.some(({
        'code': userCode,
        'id': userId,
      }) => {
        return userCode === code && userId !== id
      })) {
        throw new Error('工号不能重复')
      } else if ((await this.getUserDataTableData({
        tel,
      })).dataArray.some(({
        'tel': userTel,
        'id': userId,
      }) => {
        return userTel === tel && userId !== id
      })) {
        throw new Error('电话不能重复')
      }
      try {
        if (await modify({
          id,
          'version': await getUserDataVersionById(id),
          ...data,
        })) {
          $message({
            'message': '修改成功',
            'type': 'success',
          })
          return
        }
      } catch (error) {
        console.error(error)
      }
      throw new Error('修改用户数据时出错')
    },
    /**
     * 获取`角色分配器`的数据
     * @return {Promise<{
     *   'dataArray': {
     *     'code': String,
     *     'id': String,
     *     'name': String,
     *     'remark': String,
     *   }[],
     *   'total': Number,
     * }>}
     */
    async 'getRoleAllocatorData' () {
      const {
        roleAllocator,
      } = this
      const {
        pagination,
      } = roleAllocator
      const {
        number,
        size,
      } = pagination
      try {
        const {
          data,
          total,
        } = await queryRoleArray({
          'pageNum': number,
          'pageSize': size,
        })
        return {
          'dataArray': data.map(({
            code,
            id,
            name,
            remark,
          }) => {
            return {
              code,
              id,
              name,
              remark,
            }
          }),
          'total': Number(total),
        }
      } catch (error) {
        console.error(error)
      }
      throw new Error('查询角色列表数据时出错')
    },
    /**
     * 获取`用户数据表格`的数据
     * @param {{
     *   'code': String,
     *   'departmentId': String,
     *   'name': String,
     *   'positionId': String,
     *   'roleId': String,
     *   'tel': String,
     * }} queryParameters 查询参数
     * @return {Promise<{
     *   'dataArray': UserDataTableData[],
     *   'total': Number,
     * }>}
     */
    async 'getUserDataTableData' (queryParameters = {
      ...this.queryForm.data,
      ...this.subsystemManager.queryParameters,
    }) {
      const {
        userDataTable,
      } = this
      const {
        pagination,
      } = userDataTable
      const {
        number,
        size,
      } = pagination
      try {
        const {
          data,
          total,
        } = await commonQuery({
          'pageNum': number,
          'pageSize': size,
          ...queryParameters,
        })
        return {
          'dataArray': data.map(({
            birthday,
            code,
            company,
            department,
            id,
            name,
            position,
            roleList,
            sex,
            status,
            tel,
          }) => {
            const role = roleList?.map(({
              'name': roleName,
            }) => {
              return roleName
            }).join(' ')
            return {
              'birthday': birthday?.slice(0, 10),
              code,
              'company': company?.name,
              'department': department?.name,
              id,
              name,
              'position': position?.name,
              role,
              // eslint-disable-next-line array-element-newline
              'sex': ['男', '女'][sex],
              status,
              tel,
            }
          }),
          'total': Number(total),
        }
      } catch (error) {
        console.error(error)
      }
      throw new Error('查询用户数据时出错')
    },
    /**
     * 处理`控制按钮组`的`增加`按钮的点击事件
     */
    'handleControlButtonGroupAdd' () {
      const {
        $refs,
        userDataForm,
      } = this
      userDataForm.mode = 'add'
      userDataForm.isVisible = true
      userDataForm.data = {
        'birthday': '',
        'code': '',
        'departmentId': '',
        'email': '',
        'name': '',
        'other': '',
        'password': '',
        'positionId': '',
        'remark': '',
        'roleList': [],
        'sex': null,
        'tel': '',
      }
      this.$nextTick(() => {
        $refs.userDataFormRef.setInnerModel()
      })
    },
    /**
     * 处理`控制按钮组`的`子系统管理器`开关按钮的点击事件
     */
    async 'handleControlButtonGroupArrowToggle' () {
      const {
        $message,
        subsystemManager,
      } = this
      if (subsystemManager.isVisible) {
        subsystemManager.isVisible = false
        return
      }
      subsystemManager.treeData = [
        {
          'children': [],
          'label': '部门',
        },
        {
          'children': [],
          'label': '职位',
        },
        {
          'children': [],
          'label': '角色',
        },
      ]
      subsystemManager.isLoading = true
      subsystemManager.isVisible = true
      try {
        (await Promise.all([
          getDepartmentArray(),
          getPositionArray(),
          getRoleArray(),
        ])).forEach((value, index) => {
          subsystemManager.treeData[index].children = value
        })
      } catch (error) {
        $message.error(error.message)
      }
      // eslint-disable-next-line require-atomic-updates
      subsystemManager.isLoading = false
    },
    /**
     * 处理`控制按钮组`的`控制启停`下拉菜单指令的点击事件
     * @param {0 | 1} command 指令：`0`为停用，`1`为启用
     */
    async 'handleControlButtonGroupCommand' (command) {
      const {
        $message,
        controlButtonGroup,
      } = this
      controlButtonGroup.isStatusChangeButtonLoading = true
      try {
        await this.setUserDataStatus(command)
        controlButtonGroup.isStatusChangeButtonLoading = false
        await this.setUserDataTableData()
      } catch (error) {
        $message.error(error.message)
      }
      controlButtonGroup.isStatusChangeButtonLoading = false
    },
    /**
     * 处理`控制按钮组`的`复制`按钮的点击事件
     */
    async 'handleControlButtonGroupCopy' () {
      const {
        $message,
        userDataTable,
      } = this
      if (userDataTable.selectedRowArray.length !== 1) {
        $message.error('只能选择一条用户数据复制')
        return
      }
      await this.copyUserData(userDataTable.selectedRowArray[0].id)
    },
    /**
     * 处理`控制按钮组`的`删除`按钮的点击事件
     */
    async 'handleControlButtonGroupDelete' () {
      const {
        $refs,
        $message,
      } = this
      const task = async () => {
        try {
          await this.deleteSelectedUserArray()
          this.$nextTick(() => {
            $refs.userDataTableRef.clearSelection()
          })
          try {
            await this.setUserDataTableData()
          } catch (error) {
            $message.error(error.message)
          }
        } catch (error) {
          $message.error(error.message)
        }
      }
      try {
        await this.deleteConfirm(task)
      } catch {
        $message('已取消删除操作')
      }
    },
    /**
     * 处理`控制按钮组`的`刷新`按钮的点击事件
     */
    async 'handleControlButtonGroupRefresh' () {
      const {
        $confirm,
        $message,
        $refs,
        userDataTable,
      } = this
      const {
        selectedRowArray,
      } = userDataTable
      if (selectedRowArray.length > 0) {
        let action = ''
        try {
          action = await $confirm(
            '是否取消所有被勾选的表格条目的勾选状态？',
            {
              'cancelButtonText': '否',
              'confirmButtonLoading': false,
              'confirmButtonText': '是',
              'distinguishCancelAndClose': true,
              'showCancelButton': true,
              'type': 'warning',
            },
          )
        } catch (error) {
          if (error === 'close') {
            return
          }
          action = error
        }
        this.userDataTable = {
          'dataArray': [],
          'isLoading': false,
          'pagination': {
            'number': 1,
            'size': 10,
            'total': 0,
          },
          ...userDataTable,
        }
        if (action === 'confirm') {
          // 这里 this.userDataTable 的引用已经被更改，然而 userDataTable 还是原来的引用
          // 所以 this.userDataTable !== userDataTable
          // 所以下一句代码要带上 this
          this.userDataTable.selectedRowArray = []
          this.$nextTick(() => {
            $refs.userDataTableRef.clearSelection()
          })
        }
      }
      try {
        await this.setUserDataTableData()
      } catch (error) {
        $message.error(error.message)
      }
    },
    /**
     * 处理`控制按钮组`的`分配角色`按钮的点击事件
     */
    async 'handleControlButtonGroupRoleAllocate' () {
      this.roleAllocator = {
        'isLoading': false,
        'isVisible': false,
        'pagination': {
          'number': 1,
          'size': 10,
          'total': 0,
        },
        'table': {
          'dataArray': [],
          'isLoading': false,
          'selectedRowArray': [],
        },
      }
      const {
        $message,
        roleAllocator,
      } = this
      roleAllocator.isVisible = true
      roleAllocator.isLoading = true
      try {
        await this.setRoleAllocatorData()
      } catch (error) {
        $message.error(error.message)
      }
      roleAllocator.isLoading = false
    },
    /**
     * 处理`控制按钮组`的`控制启停`按钮的点击事件
     */
    'handleControlButtonGroupStatusChange' () {
      this.$message('该按钮无效，请将鼠标悬停在按钮右侧的箭头上')
    },
    /**
     * 处理`控制按钮组`的`视图管理器`展示按钮的点击事件
     */
    'handleControlButtonGroupViewManagerShow' () {
      this.viewManager.isVisible = true
    },
    /**
     * 处理`查询表单`的`查询`按钮的点击事件
     * @param {{
     *    'code': String,
     *    'name': String,
     *    'roleId': String,
     *    'tel': String,
     *  }} data `查询表单`的数据
     */
    async 'handleQueryFormQuery' (data) {
      const {
        $message,
        queryForm,
      } = this
      this.resetUserDataTablePagination()
      this.clearSubsystemManager()
      queryForm.data = data
      try {
        await this.setUserDataTableData()
      } catch (error) {
        $message.error(error.message)
      }
    },
    /**
     * 处理`查询表单`的`重置`按钮的点击事件
     *
     * 因为查询时一定会重置页码，所以这里就无需重置了
     */
    'handleQueryFormReset' () {
      this.clearQueryForm()
      this.$nextTick(() => {
        this.$refs.queryFormRef.setInnerModel()
      })
    },
    /**
     * 处理`查询表单`的选择角色下拉菜单的打开事件
     */
    async 'handleQueryFormSelectorShow' () {
      const {
        $message,
        queryForm,
      } = this
      const {
        roleSelector,
      } = queryForm
      roleSelector.array = []
      roleSelector.isLoading = true
      try {
        roleSelector.array = await getRoleArray()
      } catch (error) {
        $message.error(error.message)
      }
      roleSelector.isLoading = false
    },
    /**
     * 处理`角色分配器`的表格的页码的修改事件
     * @param {Number} number `角色分配器`的表格的页码
     */
    async 'handleRoleAllocatorPageNumChange' (number) {
      const {
        $message,
        roleAllocator,
      } = this
      const {
        pagination,
      } = roleAllocator
      pagination.number = number
      try {
        await this.setRoleAllocatorData()
      } catch (error) {
        $message.error(error.message)
      }
    },
    /**
     * 处理`角色分配器`的表格的页面容量的修改事件
     * @param {Number} size `角色分配器`的表格的页面容量
     */
    async 'handleRoleAllocatorPageSizeChange' (size) {
      const {
        $message,
        roleAllocator,
      } = this
      const {
        pagination,
      } = roleAllocator
      pagination.size = size
      try {
        await this.setRoleAllocatorData()
      } catch (error) {
        $message.error(error.message)
      }
    },
    /**
     * 处理`角色分配器`的`提交`按钮的点击事件
     * @param {Row[]} selectedRowArray 被勾选的`角色分配器`的表格的行组成的数组
     */
    async 'handleRoleAllocatorSubmit' (selectedRowArray) {
      const {
        $confirm,
        $message,
        roleAllocator,
      } = this
      const {
        table,
      } = roleAllocator
      try {
        await $confirm('分配新角色将覆盖已有角色，确定分配？', '分配确认', {
          'type': 'warning',
        })
      } catch {
        $message('已取消分配角色操作')
        return
      }
      roleAllocator.isLoading = true
      table.selectedRowArray = selectedRowArray
      try {
        await this.allocateRoleToUser()
      } catch (error) {
        roleAllocator.isLoading = false
        $message.error(error.message)
        return
      }
      roleAllocator.isVisible = false
      roleAllocator.isLoading = false
      try {
        await this.setUserDataTableData()
      } catch (error) {
        $message.error(error.message)
      }
    },
    /**
     * 处理`子系统管理器`的查询事件
     * @param {String} type 查询参数的类别
     * @param {String} data 查询参数的`id`属性
     */
    async 'handleSubsystemManagerQuery' (type, data) {
      const {
        $message,
        $refs,
        subsystemManager,
      } = this
      this.resetUserDataTablePagination()
      this.clearSubsystemManager()
      this.clearQueryForm()
      this.$nextTick(() => {
        $refs.queryFormRef.setInnerModel()
      })
      subsystemManager.queryParameters[{
        '职位': 'positionId',
        '角色': 'roleId',
        '部门': 'departmentId',
      }[type]] = data
      try {
        await this.setUserDataTableData()
      } catch (error) {
        $message.error(error.message)
      }
    },
    /**
     * 处理`用户数据表单`的`部门选择器`的下拉菜单打开事件
     */
    async 'handleUserDataFormDepartmentSelectorShow' () {
      const {
        $message,
        userDataForm,
      } = this
      const {
        departmentSelector,
      } = userDataForm
      departmentSelector.array = []
      departmentSelector.isLoading = true
      try {
        departmentSelector.array = await getDepartmentArray()
      } catch (error) {
        $message.error(error.message)
      }
      departmentSelector.isLoading = false
    },
    /**
     * 处理`用户数据表单`的`职位选择器`的下拉菜单打开事件
     */
    async 'handleUserDataFormPositionSelectorShow' () {
      const {
        $message,
        userDataForm,
      } = this
      const {
        positionSelector,
      } = userDataForm
      positionSelector.array = []
      positionSelector.isLoading = true
      try {
        positionSelector.array = await getPositionArray()
      } catch (error) {
        $message.error(error.message)
      }
      positionSelector.isLoading = false
    },
    /**
     * 处理`用户数据表单`的`角色选择器`的下拉菜单打开事件
     */
    async 'handleUserDataFormRoleSelectorShow' () {
      const {
        $message,
        userDataForm,
      } = this
      const {
        roleSelector,
      } = userDataForm
      roleSelector.array = []
      roleSelector.isLoading = true
      try {
        roleSelector.array = await getRoleArray()
      } catch (error) {
        $message.error(error.message)
      }
      roleSelector.isLoading = false
    },
    /**
     * 处理`用户数据表单`的`提交`按钮的点击事件
     * @param {UserDataFormData} formData `用户数据表单`的数据
     */
    async 'handleUserDataFormSubmit' (formData) {
      const {
        $message,
        userDataForm,
        userDataTable,
      } = this
      const {
        id,
      } = userDataForm
      userDataForm.data = formData
      userDataForm.isLoading = true
      try {
        // addUser editUser
        await this[`${userDataForm.mode}User`]()
      } catch (error) {
        $message.error(error.message)
        userDataForm.isLoading = false
        return
      }
      userDataForm.isLoading = false
      userDataForm.isVisible = false
      try {
        await this.setUserDataTableData()
        // 把最近修改的提出到表格数据数组的第一个
        const {
          dataArray,
        } = userDataTable
        const index = dataArray.findIndex((data) => {
          return data.id === id
        })
        const data = dataArray[index]
        dataArray.splice(index, 1)
        dataArray.unshift(data)
      } catch (error) {
        $message.error(error.message)
      }
    },
    /**
     * 处理`用户数据表格`的`复制`按钮的点击事件
     * @param {String} id 用户数据的`id`属性
     */
    async 'handleUserDataTableCopy' (id) {
      await this.copyUserData(id)
    },
    /**
     * 处理`用户数据表格`的`删除`按钮的点击事件
     * @param {Row} row 用户数据表格的一行
     */
    async 'handleUserDataTableDelete' (row) {
      const {
        $refs,
        $message,
      } = this
      const task = async () => {
        try {
          await this.deleteUser(row)
          this.$nextTick(() => {
            $refs.userDataTableRef.cancelRowSelection(row)
          })
          try {
            await this.setUserDataTableData()
          } catch (error) {
            $message.error(error.message)
          }
        } catch (error) {
          $message.error(error.message)
        }
      }
      try {
        await this.deleteConfirm(task)
      } catch {
        this.$message('已取消删除操作')
      }
    },
    /**
     * 处理`用户数据表格`的`编辑`按钮的点击事件
     * @param {String} id 用户数据的`id`属性
     */
    async 'handleUserDataTableEdit' (id) {
      const {
        $message,
        $refs,
        userDataForm,
      } = this
      const {
        departmentSelector,
        positionSelector,
        roleSelector,
      } = userDataForm
      userDataForm.isLoading = true
      userDataForm.mode = 'edit'
      userDataForm.id = id
      userDataForm.isVisible = true
      try {
        (await Promise.all([
          getDepartmentArray(),
          getPositionArray(),
          getRoleArray(),
        ])).forEach((value, index) => {
          [
            departmentSelector,
            positionSelector,
            roleSelector,
          ][index].array = value
        })
        userDataForm.data = await getUserDataFormData(id)
        this.$nextTick(() => {
          $refs.userDataFormRef.setInnerModel()
        })
      } catch (error) {
        $message.error(error.message)
      }
      userDataForm.isLoading = false
    },
    /**
     * 处理`用户数据表格`的页码的修改事件
     * @param {Number} number `用户数据表格`的页码
     */
    async 'handleUserDataTablePageNumChange' (number) {
      const {
        $message,
        userDataTable,
      } = this
      const {
        pagination,
      } = userDataTable
      pagination.number = number
      try {
        await this.setUserDataTableData()
      } catch (error) {
        $message.error(error.message)
      }
    },
    /**
     * 处理`用户数据表格`的页面容量的修改事件
     * @param {Number} size `用户数据表格`的页面容量
     */
    async 'handleUserDataTablePageSizeChange' (size) {
      const {
        $message,
        userDataTable,
      } = this
      const {
        pagination,
      } = userDataTable
      pagination.size = size
      try {
        await this.setUserDataTableData()
      } catch (error) {
        $message.error(error.message)
      }
    },
    /**
     * 处理`用户数据表格`的角色列点击事件
     * @param {String} id 用户数据的`id`属性
     */
    async 'handleUserDataTableRoleClick' (id) {
      const {
        $message,
        $refs,
        resourceAllocator,
      } = this
      resourceAllocator.isLoading = true
      resourceAllocator.totalDataArray = []
      resourceAllocator.checkedIdArray = []
      resourceAllocator.isVisible = true
      try {
        resourceAllocator.totalDataArray = (await treeQuery({
          'pageSize': 1000,
        })).data
        this.$nextTick(() => {
          $refs.resourceAllocatorRef.setTree()
        })
        const roleId = (await queryUserById(id)).roleList[0]?.id
        if (roleId) {
          resourceAllocator.checkedIdArray = (await treeQuery({
            'pageSize': 1000,
            roleId,
          })).data.map(({
            'id': checkedId,
          }) => {
            return checkedId
          })
        }
      } catch (error) {
        console.error(error)
        $message.error('查询角色资源时出错')
      }
      resourceAllocator.isLoading = false
    },
    /**
     * 处理`用户数据表格`中被勾选的表格的行组成的数组的修改事件
     *
     * 即有新的行被勾选或有已被勾选的行被取消了勾选
     * @param {Row[]} selectedRowArray 被勾选的表格的行组成的数组
     */
    'handleUserDataTableSelectionChange' (selectedRowArray) {
      this.userDataTable.selectedRowArray = selectedRowArray
    },
    /**
     * 处理`视图管理器`的`保存`按钮的点击事件
     *
     * 经过`视图管理器`处理后，表格列的`isVisible`属性被修改，并通过触发事件发回该父组件
     * @param {{
     *    'label': String,
     *    'isVisible': Boolean
     *    'prop': String,
     *    'width': String,
     *  }[]} columnArray 经过处理的新的表格列的数据组成的数组
     */
    'handleViewManagerSave' (columnArray) {
      this.userDataTable.columnArray = columnArray
    },
    /**
     * 重置用户数据表格的分页数据
     */
    'resetUserDataTablePagination' () {
      const {
        userDataTable,
      } = this
      const {
        pagination,
      } = userDataTable
      pagination.number = 1
      pagination.size = 10
    },
    /**
     * 设置`角色分配器`的数据
     */
    async 'setRoleAllocatorData' () {
      const {
        roleAllocator,
      } = this
      const {
        table,
        pagination,
      } = roleAllocator
      table.dataArray = []
      table.isLoading = !roleAllocator.isLoading
      try {
        const {
          dataArray,
          total,
        } = await this.getRoleAllocatorData()
        pagination.total = total
        table.dataArray = dataArray
        table.isLoading = false
      } catch (error) {
        table.isLoading = false
        throw error
      }
    },
    /**
     * 设置用户状态
     * @param {0 | 1} status 状态：`0`为停用，`1`为启用
     */
    async 'setUserDataStatus' (status) {
      const {
        $message,
        userDataTable,
      } = this
      const statusName = [
        '停用',
        '启用',
      ][status]
      const load = await Promise.all(userDataTable.selectedRowArray.map(async ({
        id,
      }) => {
        return {
          id,
          status,
          'version': await getUserDataVersionById(id),
        }
      }))
      try {
        if (await batchUpdate(load)) {
          $message({
            'message': `${statusName}成功`,
            'type': 'success',
          })
          return
        }
      } catch (error) {
        console.error(error)
      }
      throw new Error(`${statusName}用户时出错`)
    },
    /**
     * 设置`用户数据表格`的数据
     */
    async 'setUserDataTableData' () {
      const {
        userDataTable,
      } = this
      const {
        pagination,
      } = userDataTable
      userDataTable.dataArray = []
      userDataTable.isLoading = true
      try {
        const {
          dataArray,
          total,
        } = await this.getUserDataTableData()
        pagination.total = total
        userDataTable.dataArray = dataArray
        userDataTable.isLoading = false
      } catch (error) {
        userDataTable.isLoading = false
        throw error
      }
    },
  },
}
</script>

<style scoped lang="scss">
.header {
  display: flex;
  align-items: center;
}

.subsystemManager {
  margin: 16px;
}
</style>
